package com.onlyxiahui.common.action.description.handler.impl.method;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.springframework.core.MethodParameter;

import com.onlyxiahui.common.action.description.DocumentContext;
import com.onlyxiahui.common.action.description.bean.MethodData;
import com.onlyxiahui.common.action.description.bean.ModuleData;
import com.onlyxiahui.common.action.description.bean.ParameterData;
import com.onlyxiahui.common.action.description.enums.annotation.MethodRequest;
import com.onlyxiahui.common.action.description.enums.type.ActionType;
import com.onlyxiahui.common.action.description.handler.ParameterHandler;
import com.onlyxiahui.common.action.description.handler.impl.BaseMethodHandler;
import com.onlyxiahui.common.action.description.util.ActionAnnotationUtil;

/**
 * Description <br>
 * Date 2020-01-07 16:37:50<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */

public class RestMappingMethodHandler extends BaseMethodHandler {

	@Override
	public boolean support(DocumentContext context, ModuleData moduleData, Method method) {
		Annotation[] as = method.getAnnotations();
		boolean hasGetMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.GetMapping.getAnnotation(), as);
		boolean hasPostMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.PostMapping.getAnnotation(), as);
		boolean hasPutMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.PutMapping.getAnnotation(), as);
		boolean hasDeleteMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.DeleteMapping.getAnnotation(), as);
		boolean hasPatchMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.PatchMapping.getAnnotation(), as);
		return hasGetMapping || hasPostMapping || hasPutMapping || hasDeleteMapping || hasPatchMapping;
	}

	@Override
	public MethodData handle(DocumentContext context, ModuleData moduleData, Method method) {

		Annotation[] mas = method.getAnnotations();

		boolean hasGetMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.GetMapping.getAnnotation(), mas);
		boolean hasPostMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.PostMapping.getAnnotation(), mas);
		boolean hasPutMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.PutMapping.getAnnotation(), mas);
		boolean hasDeleteMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.DeleteMapping.getAnnotation(), mas);
		boolean hasPatchMapping = ActionAnnotationUtil.hasAnnotation(MethodRequest.PatchMapping.getAnnotation(), mas);
		String type = "";
		Annotation a = null;
		if (hasGetMapping) {
			a = ActionAnnotationUtil.getAnnotation(MethodRequest.GetMapping.getAnnotation(), mas);
			type = ActionType.get.type();
		}
		if (hasPostMapping) {
			a = ActionAnnotationUtil.getAnnotation(MethodRequest.PostMapping.getAnnotation(), mas);
			type = ActionType.post.type();
		}
		if (hasPutMapping) {
			a = ActionAnnotationUtil.getAnnotation(MethodRequest.PutMapping.getAnnotation(), mas);
			type = ActionType.put.type();
		}
		if (hasDeleteMapping) {
			a = ActionAnnotationUtil.getAnnotation(MethodRequest.DeleteMapping.getAnnotation(), mas);
			type = ActionType.delete.type();
		}
		if (hasPatchMapping) {
			a = ActionAnnotationUtil.getAnnotation(MethodRequest.PatchMapping.getAnnotation(), mas);
			type = ActionType.patch.type();
		}
		Object value = null;
		Object path = null;
		if (null != a) {
			value = ActionAnnotationUtil.getValue("value", a);
			path = ActionAnnotationUtil.getValue("path", a);
		}

		List<String> paths = new ArrayList<>();
		if (value instanceof String) {
			paths.add(value.toString());
		}
		if (value instanceof String[]) {
			String[] values = (String[]) value;
			if (null != values && values.length > 0) {
				for (String p : values) {
					paths.add(p);
				}
			}
		}

		if (path instanceof String) {
			paths.add(path.toString());
		}
		if (path instanceof String[]) {
			String[] values = (String[]) path;
			if (null != values && values.length > 0) {
				for (String p : values) {
					paths.add(p);
				}
			}
		}

		MethodData md = this.create(context, moduleData, method, paths, true);
		md.setPaths(paths);
		md.addMethodType(type);

		Class<?> classType = method.getDeclaringClass();
		List<ParameterData> parameters = new ArrayList<>();
		MethodParameter[] mps = initMethodParameters(method, classType);
		for (MethodParameter parameter : mps) {
			for (ParameterHandler ph : context.getParameterHandlers()) {
				if (context.getIgnoreJudgeBox().ignore(context, method, parameter, "")) {
					continue;
				}
				if (ph.support(context, moduleData, md, method, parameter)) {
					ParameterData pd = ph.handle(context, moduleData, md, method, parameter);
					if (null != pd) {
						parameters.add(pd);
					}
				}
			}
		}
		md.setParameters(parameters);
		return md;
	}
}
